import sys

from PyQt5.QtCore import Qt, QTimer, QFile
from PyQt5.QtWidgets import QDialog, QLabel, QListWidget, QTableWidget, QTreeWidget, QPushButton, QSplitter, \
    QVBoxLayout, QWidget, QHBoxLayout, QMessageBox, QListWidgetItem, QTableWidgetItem, QTreeWidgetItem, QApplication

import ships

MAC = "qt_mac_set_native_menubar" in dir()


class MainForm(QDialog):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)

        listLabel = QLabel("&List")
        self.listWidget = QListWidget()
        listLabel.setBuddy(self.listWidget)

        tableLabel = QLabel("&Table")
        self.tableWidget = QTableWidget()
        tableLabel.setBuddy(self.tableWidget)

        treeLabel = QLabel("Tre&e")
        self.treeWidget = QTreeWidget()
        treeLabel.setBuddy(self.treeWidget)

        addShipButton = QPushButton("&Add Ship")
        removeShipButton = QPushButton("&Remove Ship")
        quitButton = QPushButton("&Quit")
        if not MAC:
            addShipButton.setFocusPolicy(Qt.NoFocus)
            removeShipButton.setFocusPolicy(Qt.NoFocus)
            quitButton.setFocusPolicy(Qt.NoFocus)

        splitter = QSplitter(Qt.Horizontal)
        vbox = QVBoxLayout()
        vbox.addWidget(listLabel)
        vbox.addWidget(self.listWidget)
        widget = QWidget()
        widget.setLayout(vbox)
        splitter.addWidget(widget)
        vbox = QVBoxLayout()
        vbox.addWidget(tableLabel)
        vbox.addWidget(self.tableWidget)
        widget = QWidget()
        widget.setLayout(vbox)
        splitter.addWidget(widget)
        vbox = QVBoxLayout()
        vbox.addWidget(treeLabel)
        vbox.addWidget(self.treeWidget)
        widget = QWidget()
        widget.setLayout(vbox)
        splitter.addWidget(widget)
        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(addShipButton)
        buttonLayout.addWidget(removeShipButton)
        buttonLayout.addStretch()
        buttonLayout.addWidget(quitButton)
        layout = QVBoxLayout()
        layout.addWidget(splitter)
        layout.addLayout(buttonLayout)
        self.setLayout(layout)

        self.tableWidget.itemChanged.connect(self.tableItemChanged)
        addShipButton.clicked.connect(self.addShip)
        removeShipButton.clicked.connect(self.removeShip)
        quitButton.clicked.connect(self.accept)

        self.ships = ships.ShipContainer("ships.dat")
        self.setWindowTitle("Ships (dict)")
        QTimer.singleShot(0, self.initialLoad)

    def initialLoad(self):
        if not QFile.exists(self.ships.filename):
            for ship in ships.generateFakeShips():
                self.ships.addShip(ship)
            self.ships.dirty = False
        else:
            try:
                self.ships.load()
            except IOError as e:
                QMessageBox.warning(self, "Ships - Error",
                                    "Failed to load: {}".format(e))
        self.populateList()
        self.populateTable()
        self.tableWidget.sortItems(0)
        self.populateTree()

    def reject(self):
        self.accept()

    def accept(self):
        if (self.ships.dirty and
                QMessageBox.question(self, "Ships - Save?",
                                     "Save unsaved changes?",
                                     QMessageBox.Yes | QMessageBox.No) ==
                QMessageBox.Yes):
            try:
                self.ships.save()
            except IOError as e:
                QMessageBox.warning(self, "Ships - Error",
                                    "Failed to save: {}".format(e))
        QDialog.accept(self)

    def populateList(self, selectedShip=None):
        """生成列表，比较简单"""
        selected = None
        self.listWidget.clear()
        for ship in self.ships.inOrder():
            item = QListWidgetItem("{} of {}/{} ({:,})".format(
                ship.name, ship.owner, ship.country, ship.teu))
            self.listWidget.addItem(item)
            if selectedShip is not None and selectedShip == id(ship):
                selected = item
        if selected is not None:
            selected.setSelected(True)
            self.listWidget.setCurrentItem(selected)

    def populateTable(self, selectedShip=None):
        """生成表格"""
        selected = None
        self.tableWidget.clear()
        self.tableWidget.setSortingEnabled(False)  # 开始不可排序
        self.tableWidget.setRowCount(len(self.ships))  # 确定行数
        headers = ["Name", "Owner", "Country", "Description", "TEU"]  # 表头文字
        self.tableWidget.setColumnCount(len(headers))  # 列数
        self.tableWidget.setHorizontalHeaderLabels(headers)  # 装入表头文字
        for row, ship in enumerate(self.ships):
            item = QTableWidgetItem(ship.name)
            item.setData(Qt.UserRole, int(id(ship)))  # 生成一个带有user Data的项
            if selectedShip is not None and selectedShip == id(ship):
                selected = item
            self.tableWidget.setItem(row, ships.NAME, item)  # 然后把这个项填充到单元格
            self.tableWidget.setItem(row, ships.OWNER,
                                     QTableWidgetItem(ship.owner))
            self.tableWidget.setItem(row, ships.COUNTRY,
                                     QTableWidgetItem(ship.country))
            self.tableWidget.setItem(row, ships.DESCRIPTION,
                                     QTableWidgetItem(ship.description))
            item = QTableWidgetItem("{:10}".format(ship.teu))  # 生在一个带有格式的项
            item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
            self.tableWidget.setItem(row, ships.TEU, item)  # 然后再填充到单元格
        self.tableWidget.setSortingEnabled(True)  # 恢复排序功能
        self.tableWidget.resizeColumnsToContents()  # 宽度适应内容
        if selected is not None:
            selected.setSelected(True)
            self.tableWidget.setCurrentItem(selected)

    def populateTree(self, selectedShip=None):
        selected = None
        self.treeWidget.clear()
        self.treeWidget.setColumnCount(2)
        self.treeWidget.setHeaderLabels(["Country/Owner/Name", "TEU"])
        self.treeWidget.setItemsExpandable(True)
        parentFromCountry = {}  # 以country为键，以item为值
        parentFromCountryOwner = {}  # country/owner为健，以item为值
        for ship in self.ships.inCountryOwnerOrder():  # return sorted(self.ships.values(),
            #  key=lambda x: (x.country, x.owner, x.name))
            ancestor = parentFromCountry.get(ship.country)  # 查义country对应的项，如果没有，则创建之。
            if ancestor is None:
                ancestor = QTreeWidgetItem(self.treeWidget, [
                    ship.country])  # 在构造函数中带上父对象，pyqt将会自动创建item，并适合他们的父子关系。
                # QTreeWidgetItem:Constructs a tree widget item and append it to the given parent.
                # The given list of strings will be set as the item text for each column in the item.
                parentFromCountry[ship.country] = ancestor
                # 以上生成，以country为健，item 为值的字典。ancestor是一个country文本的item,这个item的父对象是widget,

            countryowner = ship.country + "/" + ship.owner
            parent = parentFromCountryOwner.get(countryowner)  # 查找，找不到，则创建之
            if parent is None:
                parent = QTreeWidgetItem(ancestor, [ship.owner])  # 以country为父对象的项，其值是owner
                parentFromCountryOwner[countryowner] = parent

                # 以上生成字典，健是country/owner，值是item，item以owner为文本。item的父对象是ancestor

            item = QTreeWidgetItem(parent, [ship.name, "{:,}".format(ship.teu)])  # 名称和吨位信息项构成item，父对象是parent

            item.setTextAlignment(1, Qt.AlignRight | Qt.AlignVCenter)
            if selectedShip is not None and selectedShip == id(ship):
                selected = item
            self.treeWidget.expandItem(parent)
            self.treeWidget.expandItem(ancestor)

        self.treeWidget.resizeColumnToContents(0)  # 展开country
        self.treeWidget.resizeColumnToContents(1)  # 展开owner
        if selected is not None:
            selected.setSelected(True)
            self.treeWidget.setCurrentItem(selected)

    def addShip(self):
        ship = ships.Ship(" Unknown", " Unknown", " Unknown")
        self.ships.addShip(ship)
        self.populateList()
        self.populateTree()
        self.populateTable(id(ship))
        self.tableWidget.setFocus()
        self.tableWidget.editItem(self.tableWidget.currentItem())

    def tableItemChanged(self, item):
        ship = self.currentTableShip()
        if ship is None:
            return
        column = self.tableWidget.currentColumn()
        if column == ships.NAME:  # NAME, OWNER, COUNTRY, DESCRIPTION, TEU = range(5)
            ship.name = item.text().strip()
        elif column == ships.OWNER:
            ship.owner = item.text().strip()
        elif column == ships.COUNTRY:
            ship.country = item.text().strip()
        elif column == ships.DESCRIPTION:
            ship.description = item.text().strip()
        elif column == ships.TEU:
            ship.teu = int(item.text())
        self.ships.dirty = True
        self.populateList()
        self.populateTree()

    def currentTableShip(self):
        item = self.tableWidget.item(self.tableWidget.currentRow(), 0)
        if item is None:
            return None
        return self.ships.ship(int(item.data(Qt.UserRole)))

    def removeShip(self):
        ship = self.currentTableShip()
        if ship is None:
            return
        if (QMessageBox.question(self, "Ships - Remove",
                                 "Remove {} of {}/{}?".format(ship.name, ship.owner, ship.country),
                                 QMessageBox.Yes | QMessageBox.No) ==
                QMessageBox.No):
            return
        self.ships.removeShip(ship)
        self.populateList()
        self.populateTree()
        self.populateTable()


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    form = MainForm()
    form.show()
    sys.exit(app.exec())
